package com.example.xcService.pojo.channels.impl;

import com.alibaba.fastjson.JSONObject;
import com.example.xcService.pojo.channels.ChannelResult;
import com.example.xcService.pojo.channels.ChannelService;
import lombok.extern.slf4j.Slf4j;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.*;

/*
* 白妙
* */
@Slf4j
public class Plugin_ECARD_P036 implements ChannelService {

    private final static String DES = "DES";

    @Override
    public ChannelResult QueryBalance(JSONObject apiConfig) {
        System.out.println("成功调用了QueryBalance");
        return  ChannelResult.success("success");
    }

    @Override
    public ChannelResult Submit(JSONObject apiConfig, Map<String, Object> data) {
        try {
            HashMap<String, String> encryptParams = new HashMap<>();

            String platForMid = apiConfig.getString("PlatForMid");
            String security = apiConfig.getString("Security");
            String submitUrl = apiConfig.getString("SubmitUrl");
            String accountVal = String.valueOf(data.get("AccountVal"));
            String supProductId = String.valueOf(data.get("SUPProductId"));

            encryptParams.put("platformid",platForMid);
            encryptParams.put("security",security);
            platForMid = platForMid+data.get("ChannelOrderCode");
            encryptParams.put("mobile",accountVal);
            encryptParams.put("userorderno",platForMid);
            long timestamp = System.currentTimeMillis() / 1000;
            encryptParams.put("timestamp",String.valueOf(timestamp));
            encryptParams.put("productid",supProductId);
            String sourceStr = createLinkString(encryptParams);
            String sign = md5Encrypt(sourceStr);

            String encryptMobile = encrypt(accountVal, security);
            String encryptProductId = encrypt(supProductId, security);
            HashMap<String, String> submitParams = new HashMap<>();
            submitParams.put("mobile",encryptMobile);
            submitParams.put("userorderno",platForMid);
            submitParams.put("timestamp",String.valueOf(timestamp));
            submitParams.put("productid",encryptProductId);
            submitParams.put("sign",sign);

            String respStr = sendPostToBM(submitParams, apiConfig.getString("PlatForMid"), submitUrl);
            JSONObject respObj = JSONObject.parseObject(respStr);
            String resultCode = respObj.getString("resultcode");
            String msg = respObj.getString("resultdescription");
            if (resultCode.equals("00000") || resultCode.equals("10005")){
                return ChannelResult.IN_PROCESS("充值中");
            }
            if (resultCode.equals("10019")||resultCode.equals("20015")||resultCode.equals("20006")||resultCode.equals("20016")) {
                return ChannelResult.error(msg);
            }
            return ChannelResult.FAILED(msg);
        }catch (Exception e) {
            e.printStackTrace();
            log.error("白妙提单接口错误：",e);
            return  ChannelResult.error("白妙提单接口错误");
        }

    }

    @Override
    public ChannelResult Query(JSONObject apiConfig, Map<String, Object> data) {

        try {
            String platForMid = apiConfig.getString("PlatForMid");
            String security = apiConfig.getString("Security");
            String queryUrl = apiConfig.getString("QueryUrl");

            HashMap<String, String> encryptParams = new HashMap<>();
            encryptParams.put("platformid", platForMid);
            encryptParams.put("security", security);
            platForMid = platForMid + data.get("ChannelOrderCode");
            encryptParams.put("userorderno", platForMid);
            long timestamp = System.currentTimeMillis() / 1000;
            encryptParams.put("timestamp", String.valueOf(timestamp));
            String sourceStr = createLinkString(encryptParams);
            String sign = md5Encrypt(sourceStr);

            HashMap<String, String> queryParams = new HashMap<>();
            queryParams.put("userorderno", platForMid);
            queryParams.put("timestamp", String.valueOf(timestamp));
            queryParams.put("sign", sign);

            String respStr = sendPostToBM(queryParams, apiConfig.getString("PlatForMid"), queryUrl);
            JSONObject respObj = JSONObject.parseObject(respStr);
            String resultCode = respObj.getString("resultcode");
            String msg = respObj.getString("resultdescription");

            if (resultCode.equals("0")) {
                return ChannelResult.success("充值成功");
            }
            if (resultCode.equals("1")) {
                return ChannelResult.FAILED(msg);
            }
            if (resultCode.equals("2")){
                return ChannelResult.IN_PROCESS("充值中");
            }
            return ChannelResult.error(msg);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("白妙查询接口错误：", e);
            return ChannelResult.error("白妙查询接口错误");
        }

    }


    @Override
    public ChannelResult Notify(JSONObject apiConfig, Map<String, Object> data) {
        System.out.println("成功调用了Notify");
        return  ChannelResult.success("success");
    }



    public static String sendPostToBM(HashMap<String,String> params,String platForMid,String urlParam) throws IOException {
        StringBuffer stringBuffer = new StringBuffer();
        URL url = new URL(urlParam);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        //			connection.setDoInput(true);
        connection.setDoOutput(true);
        String tmpplatformid = "platformid="+"\""+platForMid+"\"";
        connection.setRequestProperty("Authorization", tmpplatformid);
        connection.setRequestProperty("Accept",  "application/json;charset=UTF-8");
        connection.setRequestProperty("Content-Type","application/json");

        // Post 请求不能使用缓存
        connection.setUseCaches(false);
        OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
        out.write(JSONObject.toJSONString(params));
        out.flush();
        out.close();
        log.info("请求"+connection+"?"+JSONObject.toJSONString(params));
        BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(),"UTF-8"));
        String responseLine = "";

        while((responseLine = reader.readLine()) != null) {
            stringBuffer.append(new String(responseLine.getBytes()));
        }
        log.info("响应"+JSONObject.toJSONString(stringBuffer));
       return stringBuffer.toString();
    }



    public static String md5Encrypt(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] messageDigest = md.digest(input.getBytes());
            StringBuilder hexString = new StringBuilder();
            for (byte b : messageDigest) {
                hexString.append(String.format("%02X", b));
            }
            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * Description 根据键值进行加密
     * @param data
     * @param key  加密键byte数组
     * @return
     * @throws Exception
     */
    public static String encrypt(String data, String key) throws Exception {
        byte[] bt = encrypt(data.getBytes(), key.getBytes());
        String strs = new BASE64Encoder().encode(bt);
        return strs;
    }

    /**
     * Description 根据键值进行解密
     * @param data
     * @param key  加密键byte数组
     * @return
     * @throws Exception
     */
    public static String decrypt(String data, String key) throws IOException,
            Exception {
        if (data == null)
            return null;
        BASE64Decoder decoder = new BASE64Decoder();
        byte[] buf = decoder.decodeBuffer(data);
        byte[] bt = decrypt(buf,key.getBytes());
        return new String(bt);
    }

    /**
     * Description 根据键值进行加密
     * @param data
     * @param key  加密键byte数组
     * @return
     * @throws Exception
     */
    private static byte[] encrypt(byte[] data, byte[] key) throws Exception {
        // 生成一个可信任的随机数源
        SecureRandom sr = new SecureRandom();

        // 从原始密钥数据创建DESKeySpec对象
        DESKeySpec dks = new DESKeySpec(key);

        // 创建一个密钥工厂，然后用它把DESKeySpec转换成SecretKey对象
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
        SecretKey securekey = keyFactory.generateSecret(dks);

        // Cipher对象实际完成加密操作
        Cipher cipher = Cipher.getInstance(DES);

        // 用密钥初始化Cipher对象
        cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);

        return cipher.doFinal(data);
    }


    /**
     * Description 根据键值进行解密
     * @param data
     * @param key  加密键byte数组
     * @return
     * @throws Exception
     */
    private static byte[] decrypt(byte[] data, byte[] key) throws Exception {
        // 生成一个可信任的随机数源
        SecureRandom sr = new SecureRandom();

        // 从原始密钥数据创建DESKeySpec对象
        DESKeySpec dks = new DESKeySpec(key);

        // 创建一个密钥工厂，然后用它把DESKeySpec转换成SecretKey对象
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
        SecretKey securekey = keyFactory.generateSecret(dks);

        // Cipher对象实际完成解密操作
        Cipher cipher = Cipher.getInstance(DES);

        // 用密钥初始化Cipher对象
        cipher.init(Cipher.DECRYPT_MODE, securekey, sr);

        return cipher.doFinal(data);
    }


    public static  String createLinkString(Map<String, String> params) {
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);
        String prestr = "";
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            if (i == keys.size() - 1) {//拼接时，不包括最后一个&字符
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }
        return prestr;
    }



}
